﻿/*
    Copyright 2010, 2011 Eric Wong
	contact@optimalcycling.com
	http://www.optimalcycling.com
	Optimal Cycling - Advanced power pacing program for cyclists
	
	This file is part of Optimal Cycling.

    Optimal Cycling is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Optimal Cycling is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with Optimal Cycling.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef _FILE_RANDOM_NUMBER_GEN_H_
#define _FILE_RANDOM_NUMBER_GEN_H_

#ifndef __OPENCL_VERSION__
	#include "Options.h"
#endif

// Period of 2^128-1
// 32 bit integers
inline uint xorShiftRNG128Vect(__global uint4* rngSeeds) 
{ 
  uint t = ((*rngSeeds).s0)^(((*rngSeeds).s0)<<15);
  ((*rngSeeds).s0)=((*rngSeeds).s1); 
  ((*rngSeeds).s1)=((*rngSeeds).s2); 
  ((*rngSeeds).s2)=((*rngSeeds).s3);
  return ((*rngSeeds).s3) = (((*rngSeeds).s3)^(((*rngSeeds).s3) >> 21))^(t^(t>>4)); 
}


//inline uint randUIntBounded(__global uint4* rngSeeds, const uint low, const uint high)
//{
//	return xorShiftRNG128Vect(rngSeeds) % (high - low + 1) + low;
//}

// Using 64-bit longs
inline ulong64 randULongBounded(__global uint4* rngSeeds, const ulong64 low, const ulong64 high)
{
	ulong64 randVal1 = (ulong64)xorShiftRNG128Vect(rngSeeds);
	ulong64 randVal2 = (ulong64)xorShiftRNG128Vect(rngSeeds);

	// NOTE: Modulus bias will occur if (high - low + 1) is similar in magnitude to 2^64 
	return ((randVal1 << 32) | randVal2) % (high - low + 1) + low;
}

// Must clamp
inline real randReal(__global uint4* rngSeeds) 
{
	ulong64 randVal1 = (ulong64)xorShiftRNG128Vect(rngSeeds);
	ulong64 randVal2 = (ulong64)xorShiftRNG128Vect(rngSeeds);
	
	return clamp(real_divide((real)((randVal1 << 32) | randVal2), (real)MAX_ULONG), 0, ONE);

	//return clamp(real_divide((real)xorShiftRNG128Vect(rngSeeds), (real)MAX_UINT), (real)0, (real)1);
}

inline real randRealTraditional(__global uint4* rngSeeds) 
{
	ulong64 randVal1 = (ulong64)xorShiftRNG128Vect(rngSeeds);
	ulong64 randVal2 = (ulong64)xorShiftRNG128Vect(rngSeeds);
	
	return clamp(real_divide((real)((randVal1 << 32) | randVal2), (real)MAX_ULONG + ONE), 0, ONE - SMALL_REAL);	

	//return clamp(real_divide((real)xorShiftRNG128Vect(rngSeeds), (real)MAX_UINT), (real)0, ONE - SMALL_REAL);
}

// Must clamp
inline real randRealBounded(__global uint4* rngSeeds, const real low, const real high) 
{
	return clamp(randReal(rngSeeds) * (high - low) + low, low, high);		
}

#endif		// _FILE_RANDOM_NUMBER_GEN_H_






